home *** CD-ROM | disk | FTP | other *** search
- /*----------------------------------------------------------------------------
-
- memutil.c
-
- This reusable module contains miscellaneous memory management
- utility routines.
-
- Copyright © 1994-1995, Northwestern University.
-
- ----------------------------------------------------------------------------*/
-
- #include <string.h>
-
- #include "def.h"
- #include "memutil.h"
-
-
-
- static Size gCushion; /* size of memory cushion */
- static Size gReserve; /* size of memory reserve */
- static Handle gReserveBlock = nil; /* reserve block */
- static Boolean gCritical = true; /* true if current memory request is critical */
- static Boolean gCriticalSeq = false; /* true if in sequence of critical memory requests */
-
-
-
- /*----------------------------------------------------------------------------
- MemoryAvailable
-
- Check to see if memory is available, without using the cushion and reserve.
-
- Entry: len = size of block to allocate.
-
- Exit: function result = true if memory is available.
- ----------------------------------------------------------------------------*/
-
- Boolean MemoryAvailable (Size len)
- {
- long total, contig;
-
- if (gReserveBlock == nil || *gReserveBlock == nil) {
- if (!RecoverReserveMemory()) return false;
- }
- PurgeSpace(&total, &contig);
- return len + gCushion < contig;
- }
-
-
-
- /*----------------------------------------------------------------------------
- MyNewHandle
-
- Allocate a new relocatable block. The contents of the new block are
- cleared.
-
- Entry: len = size of block to allocate.
-
- Exit: *handle = new handle.
- function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr MyNewHandle (Size len, void *handle)
- {
- len = (Size)StripAddress((Ptr)len);
- if (!gCriticalSeq && !MemoryAvailable(len)) return memFullErr;
- gCritical = gCriticalSeq;
- *(Handle*)handle = NewHandleClear(len);
- gCritical = true;
- return MemError();
- }
-
-
-
- /*----------------------------------------------------------------------------
- MyNewHandleCritical
-
- Allocate a critical new relocatable block. The contents of the new block are
- cleared. This function is for critical memory only - it is permitted to
- use the memory cushion and reserve.
-
- Entry: len = size of block to allocate.
-
- Exit: *handle = new handle.
- function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr MyNewHandleCritical (Size len, void *handle)
- {
- len = (Size)StripAddress((Ptr)len);
- *(Handle*)handle = NewHandleClear(len);
- return MemError();
- }
-
-
-
- /*----------------------------------------------------------------------------
- MyDisposeHandle
-
- Dispose a relocatable block.
-
- Entry: handle = handle to block.
- ----------------------------------------------------------------------------*/
-
- void MyDisposeHandle (void *handle)
- {
- if (handle == nil) return;
- DisposeHandle((Handle)handle);
- }
-
-
-
- /*----------------------------------------------------------------------------
- MyNewPtr
-
- Allocate a new nonrelocatable block. The contents of the new block are
- cleared.
-
- Entry: len = size of block to allocate.
-
- Exit: *ptr = new pointer.
- function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr MyNewPtr (Size len, void *ptr)
- {
- len = (Size)StripAddress((Ptr)len);
- if (!gCriticalSeq && !MemoryAvailable(len)) return memFullErr;
- gCritical = gCriticalSeq;
- *(Ptr*)ptr = NewPtrClear(len);
- gCritical = true;
- return MemError();
- }
-
-
-
- /*----------------------------------------------------------------------------
- MyNewPtrCritical
-
- Allocate a critical new nonrelocatable block. The contents of the new
- block are cleared. This function is for critical memory only - it is
- permitted to use the memory cushion and reserve.
-
- Entry: len = size of block to allocate.
-
- Exit: *ptr = new pointer.
- function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr MyNewPtrCritical (Size len, void *ptr)
- {
- len = (Size)StripAddress((Ptr)len);
- *(Ptr*)ptr = NewPtrClear(len);
- return MemError();
- }
-
-
-
- /*----------------------------------------------------------------------------
- MyDisposePtr
-
- Dispose a nonrelocatable block.
-
- Entry: ptr = pointer to block.
- ----------------------------------------------------------------------------*/
-
- void MyDisposePtr (void *ptr)
- {
- if (ptr == nil) return;
- DisposePtr((Ptr)ptr);
- }
-
-
-
- /*----------------------------------------------------------------------------
- MySetHandleSize
-
- Change the size of a relocatable block.
-
- Entry: handle = handle to block.
- len = new size of block.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr MySetHandleSize (void *handle, Size len)
- {
- Size oldLen;
- OSErr err = noErr;
-
- len = (Size)StripAddress((Ptr)len);
- oldLen = GetHandleSize(handle);
- if (!gCriticalSeq && oldLen < len) {
- if (!MemoryAvailable(len-oldLen)) return memFullErr;
- }
- gCritical = gCriticalSeq;
- SetHandleSize(handle, len);
- gCritical = true;
- err = MemError();
- if (err == memFullErr) {
- /* The Memory Manager is too stupid to do this itself. */
- MoveHHi(handle);
- CompactMem(maxSize);
- gCritical = gCriticalSeq;
- SetHandleSize(handle, len);
- gCritical = true;
- err = MemError();
- }
- if (err != noErr) return err;
- if (oldLen >= len) return noErr;
- if (gCriticalSeq || MemoryAvailable(0)) return noErr;
- SetHandleSize(handle, oldLen);
- return memFullErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- MySetHandleSizeCritical
-
- Change the size of a critical relocatable block. This function is for
- critical memory only - it is permitted to use the memory cushion and
- reserve.
-
- Entry: handle = handle to block.
- len = new size of block.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr MySetHandleSizeCritical (void *handle, Size len)
- {
- len = (Size)StripAddress((Ptr)len);
- SetHandleSize(handle, len);
- if (MemError() == memFullErr) {
- /* The Memory Manager is too stupid to do this itself. */
- MoveHHi(handle);
- CompactMem(maxSize);
- SetHandleSize(handle, len);
- }
- return MemError();
- }
-
-
-
- /*----------------------------------------------------------------------------
- MyGetHandleSize
-
- Get the size of a relocatable block.
-
- Entry: handle = handle to block.
-
- Exit: function result = size of block.
- ----------------------------------------------------------------------------*/
-
- long MyGetHandleSize (void *handle)
- {
- return GetHandleSize((Handle)handle);
- }
-
-
-
- /*----------------------------------------------------------------------------
- MyHandToHand
-
- Create a new relocatable block and copy an old relocatable block to it.
-
- Entry: *handle = handle to block.
-
- Exit: function result = error code.
- *handle = handle to new copy of block.
- ----------------------------------------------------------------------------*/
-
- OSErr MyHandToHand (void *theHndl)
- {
- OSErr err = noErr;
-
- if (!gCriticalSeq && !MemoryAvailable(GetHandleSize(*(Handle*)theHndl)))
- return memFullErr;
- gCritical = gCriticalSeq;
- err = HandToHand((Handle*)theHndl);
- gCritical = true;
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- MyHandAndHand
-
- Copy a relocatable block to the end of another relocatable block.
-
- Entry: srcHandle = source handle.
- destHandle = destination handle.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr MyHandAndHand (void *srcHandle, void *destHandle)
- {
- long srcLen, destLen;
- OSErr err = noErr;
-
- if (srcHandle == nil) return noErr;
- srcLen = GetHandleSize(srcHandle);
- destLen = GetHandleSize(destHandle);
- err = MySetHandleSize(destHandle, srcLen + destLen);
- if (err != noErr) return err;
- BlockMoveData(*(Ptr*)srcHandle, *(Ptr*)destHandle + destLen, srcLen);
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- MyPtrAndHand
-
- Append data to the end of a relocatable block.
-
- Entry: srcPtr = source pointer.
- destHandle = destination handle.
- len = amount of data to append.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr MyPtrAndHand (void *srcPtr, void *destHandle, Size len)
- {
- OSErr err = noErr;
-
- len = (Size)StripAddress((Ptr)len);
- if (!gCriticalSeq && !MemoryAvailable(len)) return memFullErr;
- gCritical = gCriticalSeq;
- err = PtrAndHand(srcPtr, destHandle, len);
- gCritical = true;
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- MyStrAndHand
-
- Append a C-format string to the end of a relocatable block.
-
- Entry: str = C-format string.
- destHandle = destination handle.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr MyStrAndHand (char *str, void *destHandle)
- {
- return MyPtrAndHand(str, destHandle, strlen(str));
- }
-
-
-
- /*----------------------------------------------------------------------------
- MyPtrToHand
-
- Create a new relocatable block and copy data into it.
-
- Entry: srcPtr = source pointer.
- len = amount of data to copy.
-
- Exit: function result = error code.
- *destHandle = new handle.
- ----------------------------------------------------------------------------*/
-
- OSErr MyPtrToHand (void *srcPtr, void *destHandle, Size len)
- {
- OSErr err = noErr;
-
- len = (Size)StripAddress((Ptr)len);
- if (!gCriticalSeq && !MemoryAvailable(len)) return memFullErr;
- gCritical = gCriticalSeq;
- err = PtrToHand(srcPtr, destHandle, len);
- gCritical = true;
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- MyPtrToXHand
-
- Copy data into an existing relocatable block.
-
- Entry: srcPtr = source pointer.
- destHandle = destination handle.
- len = amount of data to copy.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr MyPtrToXHand (void *srcPtr, void *destHandle, Size len)
- {
- Size oldLen;
- OSErr err = noErr;
-
- len = (Size)StripAddress((Ptr)len);
- oldLen = GetHandleSize(destHandle);
- if (!gCriticalSeq && oldLen < len) {
- if (!MemoryAvailable(len - oldLen)) return memFullErr;
- }
- gCritical = gCriticalSeq;
- err = PtrToXHand(srcPtr, destHandle, len);
- gCritical = true;
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- MyHLock
-
- Lock a relocatable block.
-
- Entry: handle = handle to lock.
- ----------------------------------------------------------------------------*/
-
- void MyHLock (void *handle)
- {
- if (handle == nil) return;
- HLock((Handle)handle);
- }
-
-
-
- /*----------------------------------------------------------------------------
- MyHLockHi
-
- Move a relocatable block high and lock it.
-
- Entry: handle = handle to lock.
- ----------------------------------------------------------------------------*/
-
- void MyHLockHi (void *handle)
- {
- if (handle == nil) return;
- HLockHi((Handle)handle);
- }
-
-
-
- /*----------------------------------------------------------------------------
- MyHUnlock
-
- Unlock a relocatable block.
-
- Entry: handle = handle to unlock.
- ----------------------------------------------------------------------------*/
-
- void MyHUnlock (void *handle)
- {
- if (handle == nil) return;
- HUnlock((Handle)handle);
- }
-
-
-
- /*----------------------------------------------------------------------------
- MyHGetState
-
- Get the state of a memory block.
-
- Entry: handle = handle to memory block.
-
- Exit: function result = state.
- ----------------------------------------------------------------------------*/
-
- char MyHGetState (void *handle)
- {
- return HGetState(handle);
- }
-
-
-
- /*----------------------------------------------------------------------------
- MyHSetState
-
- Set the state of a memory block.
-
- Entry: handle = handle to memory block.
- state = state to set.
- ----------------------------------------------------------------------------*/
-
- void MyHSetState (void *handle, char state)
- {
- HSetState(handle, state);
- }
-
-
-
- /*----------------------------------------------------------------------------
- MyGrowZone
-
- Grow zone function for critical memory requests.
-
- Entry: cbNeeded = amount of memory needed.
-
- Exit: function result = number of bytes freed.
- ----------------------------------------------------------------------------*/
-
- static pascal long MyGrowZone (Size cbNeeded)
- {
- long theA5, result;
-
- theA5 = SetCurrentA5();
- if (gCritical && gReserveBlock != nil &&
- *gReserveBlock != nil && gReserveBlock != GZSaveHnd())
- {
- EmptyHandle(gReserveBlock);
- result = gReserve;
- } else {
- result = 0;
- }
- SetA5(theA5);
- return result;
- }
-
-
-
- /*----------------------------------------------------------------------------
- BeginCriticalMemorySequence
-
- Begin a sequence of critical memory requests (e.g., when saving a file).
-
- Exit: savedCriticalSeq = previous value of the critical memory
- sequence state. The caller must restore this value on the
- matching call to EndCriticalMemorySequence.
- ----------------------------------------------------------------------------*/
-
- void BeginCriticalMemorySequence (Boolean *savedCriticalSeq)
- {
- *savedCriticalSeq = gCriticalSeq;
- gCriticalSeq = true;
- }
-
-
-
- /*----------------------------------------------------------------------------
- EndCriticalMemorySequence
-
- End a sequence of critical memory requests.
-
- Entry: savedCriticalSeq = previous value of the critical memory
- sequence state, as returned on the matching call to
- BeginCriticalMemorySequence.
- ----------------------------------------------------------------------------*/
-
- void EndCriticalMemorySequence (Boolean savedCriticalSeq)
- {
- gCriticalSeq = savedCriticalSeq;
- }
-
-
-
- /*----------------------------------------------------------------------------
- HaveModernTempMemory
-
- Check to see if we have modern temporary memory (real and tracked).
-
- Exit: function result = true if we have modern temporary memory.
- ----------------------------------------------------------------------------*/
-
- Boolean HaveModernTempMemory (void)
- {
- OSErr err = noErr;
- long response;
-
- #define mask ((1L << gestaltTempMemSupport) | \
- (1L << gestaltRealTempMemory) | \
- (1L << gestaltTempMemTracked))
-
- err = Gestalt(gestaltOSAttr, &response);
- if (err != noErr) return false;
- return (response & mask) == mask;
- }
-
-
-
- /*----------------------------------------------------------------------------
- MyTempNewHandle
-
- Allocate temporary memory.
-
- Entry: len = size of block to allocate.
-
- Exit: *handle = new handle.
- function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr MyTempNewHandle (Size len, void *handle)
- {
- OSErr err = noErr;
-
- *(Handle*)handle = TempNewHandle(len, &err);
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- InitMemUtil
-
- Initialize the memory utilities.
-
- Entry: cushion = size of memory cushion.
- reserve = size of memory reserve block.
-
- Exit: function result = error code.
-
- For a description of the memory cushion and reserve, see NIM:Memory.
- ----------------------------------------------------------------------------*/
-
- OSErr InitMemUtil (Size cushion, Size reserve)
- {
- OSErr err = noErr;
- static GrowZoneUPP myGrowZoneUPP;
-
- gCushion = cushion;
- gReserve = reserve;
- gReserveBlock = NewHandle(reserve);
- err = MemError();
- if (err != noErr) return err;
- myGrowZoneUPP = NewGrowZoneProc(MyGrowZone);
- SetGrowZone(myGrowZoneUPP);
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- RecoverReserveMemory
-
- Recover the reserve memory block, if possible. This function should be
- called in the main event loop.
-
- Exit: function result = true if reserve block recovered and memory
- cushion available.
- ----------------------------------------------------------------------------*/
-
- Boolean RecoverReserveMemory (void)
- {
- if (gReserveBlock == nil) return true;
- if (*gReserveBlock != nil) return true;
- ReallocateHandle(gReserveBlock, gReserve);
- if (MemError() != noErr) return false;
- return MemoryAvailable(0);
- }
-